/*
 * Copyright 2003-2007 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

package com.colony.networkvm.machine;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.argot.TypeException;
import com.argot.TypeLibraryWriter;
import com.argot.TypeMap;
import com.argot.TypeOutputStream;
import com.argot.TypeWriter;
import com.argot.meta.MetaAbstract;
import com.argot.remote.MetaRemoteException;
import com.colony.networkvm.instruction.NvmInstruction;
import com.colony.remote.RemoteException;

public class NvmState
{
	public static final String TYPENAME = "nvm.state";

	// items moved between systems.
	protected List _instructions;
	protected int _programCounter;
	protected NvmHeap _heap;
	protected Throwable _exception;

	public NvmState( int programCounter, NvmInstruction[] instructions, NvmHeap heap, Throwable exception )
	{
		_programCounter = programCounter;
		_instructions = new ArrayList();
		for(int x=0;x<instructions.length;x++)
		{
			_instructions.add(instructions[x]);
		}
		_heap = heap;
		_exception = exception;
	}
	
	public NvmState()
	{
		_instructions = new ArrayList();
		_heap = new NvmHeap();
		_programCounter = 0;
		_exception = null;	
	}

	public void setException( Throwable exception )
	{
		_exception = exception;
	}
	
	private static class NvmStateWriter
	implements TypeWriter
	{
		private MetaAbstract _exAbstract;
		private TypeWriter _uint16;
		private TypeWriter _nvmInstructions;
		private TypeWriter _nvmHeap;
		private TypeWriter _remoteException;
		private Integer _remoteEmptyException;

		public NvmStateWriter(TypeMap map) 
		throws TypeException
		{
			_exAbstract = (MetaAbstract) map.getStructure(map.getId("remote.exception"));
			_uint16 = map.getWriter(map.getId("u16"));
			_nvmInstructions = map.getWriter(map.getId("nvm.instructions"));
			_nvmHeap = map.getWriter(map.getId("nvm.heap"));
			_remoteException = map.getWriter(map.getId(MetaRemoteException.TYPENAME));
			_remoteEmptyException = new Integer(map.getId("remote.exception#empty"));
		}
		
		public void write(TypeOutputStream out, Object o) 
		throws TypeException, IOException
		{
			NvmState state = (NvmState)o;
			
			_uint16.write( out, new Integer( state._programCounter ));
			_nvmInstructions.write( out, state._instructions.toArray() );
			_nvmHeap.write( out, state._heap );
			if ( state._exception == null )
			{
				_uint16.write( out, _remoteEmptyException );
			}
			else
			{
				int id;
				
	            try
	            {
	                id = out.getTypeMap().getLibrary().getId( state._exception.getClass());
	            }
	            catch (TypeException e)
	            {
	            	id = -1;
	            }
	            
				if ( id == -1 || !_exAbstract.isMapped( id ))
				{
					// exception isn't mapped.  So wrap it.
					RemoteException ex = new RemoteException( state._exception.getMessage(), state._exception );					
					_remoteException.write( out, ex );
				}
				else
				{
					_remoteException.write( out, state._exception );
				}
			}
		}
	}
	
	public static class NvmStateLibraryWriter
	implements TypeLibraryWriter
	{
		public TypeWriter getWriter(TypeMap map) 
		throws TypeException 
		{
			return new NvmStateWriter(map);
		}
		
	}

}
